package com.atguigu.product.products.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import com.atguigu.product.products.entity.PmsCategoryBrandRelationEntity;
import com.atguigu.product.products.service.PmsCategoryBrandRelationService;
import com.atguigu.product.products.vo.respVo.Catelog2Vo;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.atguigu.common.utils.PageUtils;
import com.atguigu.common.utils.Query;

import com.atguigu.product.products.dao.PmsCategoryDao;
import com.atguigu.product.products.entity.PmsCategoryEntity;
import com.atguigu.product.products.service.PmsCategoryService;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;


@Service("pmsCategoryService")
public class PmsCategoryServiceImpl extends ServiceImpl<PmsCategoryDao, PmsCategoryEntity> implements PmsCategoryService {
    @Autowired
    private PmsCategoryDao pmsCategoryDao;
    @Autowired
    private PmsCategoryBrandRelationService pmsCategoryBrandRelationService;

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private RedissonClient redissonClient;


    /**
     * 商城前台服务显示所有三级分类信息--数据库查询
     *
     * @return
     */
    public Map<String, List<Catelog2Vo>> indexCatelog() {
        //查询所有的一级分类
        List<PmsCategoryEntity> categoryEntities = this.baseMapper.selectList(new QueryWrapper<PmsCategoryEntity>().eq("parent_cid", 0));
        Map<String, List<Catelog2Vo>> listMap = categoryEntities.stream().collect(Collectors.toMap(k -> k.getCatId().toString(),
                (v) -> {
                    //收集二级和三级分类信息
                    List<Catelog2Vo> catelog2VoList = null;
                    //查询对应的该一级下的所有二级信息
                    List<PmsCategoryEntity> categoryEntities1 = this.baseMapper.selectList(new QueryWrapper<PmsCategoryEntity>().eq("parent_cid", v.getCatId()));
                    if (categoryEntities1 != null && categoryEntities1.size() > 0) {
                        List<Catelog2Vo> catelog2Vos = categoryEntities1.stream().map((m) -> {
                            Catelog2Vo catelog2Vo = new Catelog2Vo();
                            catelog2Vo.setCatalog1Id(v.getCatId().toString());
                            catelog2Vo.setCatalog3List(null);
                            catelog2Vo.setId(m.getCatId().toString());
                            catelog2Vo.setName(m.getName());
                            return catelog2Vo;
                        }).collect(Collectors.toList());

                        //遍历二级获取三级
                        catelog2VoList = catelog2Vos.stream().map((m) -> {
                            //查询出所有的三级
                            List<PmsCategoryEntity> level3s = this.baseMapper.selectList(new QueryWrapper<PmsCategoryEntity>().eq("parent_cid", m.getId()));
                            if (level3s != null && level3s.size() > 0) {
                                List<Catelog2Vo.Catelog3Vo> catelog3Vos = level3s.stream().map(m1 -> {
                                    Catelog2Vo.Catelog3Vo catelog3Vo = new Catelog2Vo.Catelog3Vo();
                                    catelog3Vo.setCatalog2Id(m.getId());
                                    catelog3Vo.setId(m1.getCatId().toString());
                                    catelog3Vo.setName(m1.getName());
                                    return catelog3Vo;

                                }).collect(Collectors.toList());
                                m.setCatalog3List(catelog3Vos);
                            }
                            return m;
                        }).collect(Collectors.toList());
                    }

                    return catelog2VoList;
                }
                )
        );
        return listMap;
    }


    /**
     * 商城前台服务显示所有三级分类信息--缓存查询
     *
     * @return
     */
    public Map<String, List<Catelog2Vo>> indexCatelogRedis() {
        //查询缓存中是否存在数据
        String indexCatelogRedis = stringRedisTemplate.opsForValue().get("indexCatelogRedis");
        if (StringUtils.isEmpty(indexCatelogRedis)) {
            System.out.println("查询了数据库------------------");
            //查询数据库
            Map<String, List<Catelog2Vo>> stringListMap = indexCatelog();
            //将数据放入缓存中
            redisTemplate.opsForValue().set("indexCatelogRedis", stringListMap,30,TimeUnit.SECONDS);
//            String jsonString = JSON.toJSONString(stringListMap);
//            stringRedisTemplate.opsForValue().set("indexCatelogRedis", jsonString);
        }
        //完成数据的反序列化
//        Map<String, List<Catelog2Vo>> stringListMap = JSON.parseObject(indexCatelogRedis, new TypeReference<Map<String, List<Catelog2Vo>>>() {
//        });
        Map<String, List<Catelog2Vo>>  stringListMap = (Map<String, List<Catelog2Vo>>)redisTemplate.opsForValue().get("indexCatelogRedis");
        return stringListMap;
    }


    /**
     * 商城前台服务显示所有三级分类信息--缓存查询--redis原生分布式锁方式
     *
     * @return
     */
    public Map<String, List<Catelog2Vo>> indexCatelogRedis1() {




        String uuid = UUID.randomUUID().toString();
        //加锁设置key--保证加锁的原子性
        Boolean lock = redisTemplate.opsForValue().setIfAbsent("lock", uuid, 3000, TimeUnit.SECONDS);
        Map<String, List<Catelog2Vo>> stringListMap = null;
        if (lock) {
            try {
                stringListMap = indexCatelogRedis();
                Thread.sleep(1000);
            } catch (Exception e) {


            } finally {
                //解锁
                String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
                Long aLong = (Long) redisTemplate.execute(new DefaultRedisScript<Long>(script, Long.class)
                        , Arrays.asList("lock"), uuid);
                System.out.println("====>"+aLong);
            }

        } else {
            //一段时间后自旋
//            try {
//////                Thread.sleep(3);
////            } catch (InterruptedException e) {
////                e.printStackTrace();
////            }
            System.out.println("获取分布式锁失败...等待重试");
            try {
                Thread.sleep(200);
            } catch (Exception e) {

            }
            return indexCatelogRedis1();
        }
        return stringListMap;
    }


    /**
     * 商城前台服务显示所有三级分类信息--缓存查询--redisson方式
     *
     * @return
     */
    public Map<String, List<Catelog2Vo>> indexCatelogRedis2() {

        RLock redissonClientLock = redissonClient.getLock("indexCatelogRedis2-lock");
        //加锁-没有设置
        redissonClientLock.lock(30,TimeUnit.SECONDS);

        Map<String, List<Catelog2Vo>> stringListMap = null;
            try {
                stringListMap = indexCatelogRedis();
            } catch (Exception e) {

            } finally {
                //解锁
                redissonClientLock.unlock();
            }


        return stringListMap;
    }

    @Override
    public PageUtils queryPage(Map<String, Object> params) {
        IPage<PmsCategoryEntity> page = this.page(
                new Query<PmsCategoryEntity>().getPage(params),
                new QueryWrapper<PmsCategoryEntity>()
        );

        return new PageUtils(page);
    }

    /**
     * 递归查询所有三级数据
     *
     * @return
     */
    public List<PmsCategoryEntity> queryByTree() {

        //查询所有数据
        List<PmsCategoryEntity> categories = baseMapper.selectList(null);
        if (categories != null && categories.size() > 0) {
            //来对数据进行递归存储
            List<PmsCategoryEntity> pmsCategoryEntityList = categories.stream().filter(m -> m.getParentCid() == 0)
                    .map((m) -> {
                        m.setChildren(getChildren(m, categories));
                        return m;
                    }).collect(Collectors.toList());
            return pmsCategoryEntityList;
        }
        return null;

    }

    /**
     * 对于选中的商品做逻辑删除
     *
     * @param longs
     */
    public void deleteAllPitch(List<Long> longs) {
        pmsCategoryDao.deleteBatchIds(longs);
    }

    /**
     * 查询categoryid的递进关系
     *
     * @param catelogId
     * @return
     */
    public Long[] queryRec(Long catelogId) {
        //查询该分类信息
        List<Long> as = new ArrayList<>();
        List<Long> recursion = recursion(catelogId, as);
        //逆序
        Collections.reverse(recursion);
        return recursion.toArray(new Long[recursion.size()]);
    }

    @Transactional
    public void updateDetail(PmsCategoryEntity pmsCategory) {
        this.updateById(pmsCategory);
        //修改品牌分类关联表
        PmsCategoryBrandRelationEntity en = new PmsCategoryBrandRelationEntity();
        en.setCatelogId(pmsCategory.getCatId());
        en.setCatelogName(pmsCategory.getName());
        pmsCategoryBrandRelationService.update(en, new UpdateWrapper<PmsCategoryBrandRelationEntity>().eq("catelog_id", pmsCategory.getCatId()));
    }


    /**
     * 商品id的层级递归
     *
     * @param cate
     * @param as
     */
    public List<Long> recursion(Long cate, List<Long> as) {
        as.add(cate);
        PmsCategoryEntity pmsCategoryEntity = pmsCategoryDao.selectById(cate);
        if (pmsCategoryEntity.getParentCid() != 0) {
            recursion(pmsCategoryEntity.getParentCid(), as);
        }
        return as;
    }

    public List<PmsCategoryEntity> getChildren(PmsCategoryEntity pmsCategoryEntity, List<PmsCategoryEntity> categories) {
        //查询子类的子类信息
        List<PmsCategoryEntity> entities = categories.stream().
                filter(m -> m.getParentCid() == pmsCategoryEntity.getCatId())
                .map((m -> {
                    m.setChildren(getChildren(m, categories));
                    return m;
                })).collect(Collectors.toList());
        return entities;
    }

}